package com.hsmpay.mobile.action.forward;

import com.hsmpay.common.util.jiami.Des3;
import com.hsmpay.common.util.jiami.RSAObjectC;
import com.hsmpay.mobile.action.base.MobileBaseAction;
import com.hsmpay.mobile.pojo.device.DeviceKey;
import com.hsmpay.mobile.pojo.terminal.TerminalType;
import com.hsmpay.mobile.service.device.DeviceKeyService;
import com.hsmpay.mobile.service.terminal.TerminalTypeService;
import com.hsmpay.utils.DesUtil;
import com.hsmpay.yl8583.utils.TestDes;
import it.sauronsoftware.base64.Base64;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import com.hsmpay.utils.ToolsKt;

/**
 * 主要的用户接口  action
 */
@Controller("forwardControlAction")
@Scope("prototype")
public class ForwardControlAction extends MobileBaseAction {
    private static final long serialVersionUID = 4937766762239628830L;
    @Resource(name = "terminalTypeService")
    private TerminalTypeService<TerminalType, Long> terminalTypeService;
    @Resource(name = "deviceKeyService")
    private DeviceKeyService<DeviceKey, Long> deviceKeyService;//设备秘钥信息
    private static Logger log = Logger.getLogger(ForwardControlAction.class);
    //private RSAObjectC rsaEncrypt = null;//RSAObjectC.getInstance();
    private String action = null;
    private String clientType = null;
    private String terminalTypeId = null;
    private String roleId = null;

    /**
     * 终端——>服务器
     * BASE64(终端类型号)|BASE64(RSA(报文加密密钥))|BASE64(3DES(报文原文))
     * 服务器——>终端
     * 正常响应格式：1|BASE64(3DES(报文))|BASE64(MD5(报文))
     * 错误响应格式：0|错误码|BASE64(错误描述)
     *
     * @return
     */
    public String forwardControl() {
        //解决 RSA解密时出现的 安全问题
        String reslut = null;//this.getRequest().getParameter("xml");
        BufferedReader br = null;
        String[] resultArray = null;
        StringBuilder sb = null;
        try {
            //-------------- 从流里面读出传输数据
            br = new BufferedReader(new InputStreamReader(getRequest().getInputStream(), "utf-8"));
            String line = null;
            sb = new StringBuilder();
            for (line = br.readLine(); line != null; line = br.readLine()) {
                sb.append(line);
                //reslut+=line;
            }
            reslut = sb.toString();
//		    log.debug("解密前数据：#"+reslut+"#end");//打印客户端 传递过来的数据
            if (StringUtils.isBlank(reslut)) {//判断数据是否为空
                sendAppErrorMsg("6000", "");
                //sendAjaxResponse("测试失败！你没有传递参数");
                return null;
            }

            //----------------解析 全局参数
            resultArray = decrypt(reslut);
            if (StringUtils.isBlank(resultArray[2])) {//密文数据有误
                String message = encryptAppMsg(0, "ZYA0", "MAC校验错误，请联系管理员！");
                sendAppMsg(message);
                return null;
            }
            //----------------判断 全局参数是否为空
            JSONObject js = JSONObject.fromObject(resultArray[2]);
            //1、action
            if (js.containsKey("action")) {
                action = js.getString("action");
            }
            if (StringUtils.isBlank(action)) {
                sendAppErrorMsg("6001", "action");//发送不能为空 错误信息
                return null;
            }
            //2、clientType
            if (js.containsKey("clientType")) {
                clientType = js.getString("clientType");
            }
            if (StringUtils.isBlank(clientType)) {
                sendAppErrorMsg("6001", "clientType");//发送不能为空 错误信息
                return null;
            }
            //3、terminalTypeId
            if (js.containsKey("terminalTypeId")) {
                terminalTypeId = js.getString("terminalTypeId");
            }
            if (StringUtils.isBlank(terminalTypeId)) {
                sendAppErrorMsg("6001", "terminalTypeId");//发送不能为空 错误信息
                return null;
            }
            //4、roleId
            if (js.containsKey("roleId")) {
                roleId = js.getString("roleId");
            }
            if (StringUtils.isBlank(roleId)) {
                if (!isAllowRoleIdIsNull(action)) {
                    sendAppErrorMsg("6001", "roleId");//发送不能为空 错误信息
                    return null;
                }
            }

            log.debug("转发 action = #" + action + "#");
            log.debug("转发 clientType = " + clientType);
            log.debug("转发 terminalTypeId = " + terminalTypeId);
            log.debug("转发 roleId = " + roleId);


            //处理设备信息
//            if ("checkFunction_getVisibleFunction" != action)
            String finalResult = js.toString();
            if ( action.equals("purchase_receivablesToCard") ||
                 action.equals("purchase_secondsReceivablesToCard") ||
                 action.equals("purchase_zeroFLReceivablesToCard") ||
                 action.equals("balance_balanceEnquiry") ||
                 action.equals("creditRepayment_checkCreditBankCard") ||
                 action.equals("transfer_transfer") ||
                 action.equals("settleSecondsAction_settleSecondsTrans") ||
                 action.equals("balance_balanceEnquiry"))
                finalResult = handleDeviceInfo(js);

            //保存 参数对象到请求对象里
            getRequest().setAttribute(FC_DES3_Key, resultArray[1]);//密钥

            getRequest().setAttribute(FC_DATA, finalResult);//加密数据

            //String result = encryptAppMsg(1, "测试数据", resultArray[1]);
            //sendAppMsg("测试成功{\"msg\":\"测试成功\"}",resultArray[1]);

            return StringUtils.isBlank(action) ? null : action;
        } catch (IOException e) {
            String message = encryptAppMsg(0, "ZYA0", "MAC校验错误，请联系管理员！");
            sendAppMsg(message);
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            sendAppErrorMsg("9999", "");
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            resultArray = null;
            reslut = null;
            sb = null;
        }
        return null;
    }

    /**
     * 处理磁道信息
     *
     * @param json
     * @return
     */
    private String handleDeviceInfo(JSONObject json) throws Exception {
        String deviceId = json.containsKey("deviceId") ? json.getString("deviceId") : "";//设备id
        if(StringUtils.isBlank(deviceId)){
            return json.toString();
        }
        DeviceKey deviceKey = deviceKeyService.getDeviceKeyByDeviceId(deviceId);
        //TODO 这两个参数值针对特定的设备,如果没有这两个参数则走正常逻辑
        String track2Data = json.containsKey("track2Data") ? json.getString("track2Data") : "";//二磁道密文
        String track3Data = json.containsKey("track3Data") ? json.getString("track3Data") : "";//三磁道密文
        String pin = json.containsKey("pin") ? json.getString("pin") : "";//pin
        int machineType = json.containsKey("machineType") ? json.getInt("machineType") : deviceKey.getMachine_type(); // 设备类型
        String accountNumber = json.containsKey("accountNumber") ? json.getString("accountNumber") : "";
        log.debug("二磁道密文track2Data的值为: " + track2Data);
        log.debug("三磁道密文track3Data的值为: " + track3Data);
//        log.debug("pin密文为: " + pin);
        log.debug("设备编号deviceId的值为: " + deviceId);
        if (null == deviceKey || StringUtils.isBlank(track2Data)) {
            return json.toString();
        }
        String trkKey = deviceKey.getTrackKey();
        String pinKey = deviceKey.getPinKey();

        // i21B
        if (machineType == 8 && StringUtils.isNotBlank(trkKey)) {
            track2Data = decryptTrack(track2Data, trkKey);
            // log.debug("二磁道信息为: " + track2Data);
            json.put("track2Data", track2Data);
        } else if (machineType == 9 && StringUtils.isNotBlank(trkKey)) {
            // 截取二磁道中间部分进行解密
            int track2Len = track2Data.length();
            String midTrack2Data = DesUtil.decode3DES(track2Data.substring(track2Len - 18, track2Len - 2), trkKey);
            String result = track2Data.substring(0, track2Len - 18) + midTrack2Data + track2Data.substring(track2Len - 2);

            String pan = result.substring(0, result.toUpperCase().indexOf('D'));
            pin = ToolsKt.getPin(pin, pan, pinKey, "");
            json.put("track2Data", result);
            json.put("pin", pin);
            json.put("accountNumber", pan);
        } else if (machineType == 10 && StringUtils.isNotBlank(trkKey)) {
            // 截取二磁道中间部分进行解密
            int track2Len = track2Data.length();
            log.debug("encrypted track2data: " + track2Data);
            String midTrack2Data = track2Data.substring(track2Len - 18, track2Len - 2);
            log.debug("before decrypt, the middle of the track2Data is: " + midTrack2Data);
            midTrack2Data = DesUtil.decode3DES(midTrack2Data, trkKey);
            log.debug("after decrypt, the middle of the track2Data is: " + midTrack2Data);
            String result = track2Data.substring(0, track2Len - 18) + midTrack2Data + track2Data.substring(track2Len - 2);

            json.put("track2Data", result);
        }
        log.info("二磁道信息: " + json.getString("track2Data"));
        return json.toString();
    }

    /**
     * 解密磁道信息
     *
     * @param
     * @param trkKey
     * @return
     */
    private String decryptTrack(String trackData, String trkKey) {
        String result = "";
        if (StringUtils.isNotBlank(trackData)) {
            result = DesUtil.decode3DES(trackData, trkKey);
        }
        if (StringUtils.isNotBlank(result) && result.contains("F")) {
            result = result.substring(0, result.indexOf("F"));
        }
        return result;
    }

    /**
     * 解析xml
     *
     * @param reslut
     * @return
     */
    public String[] decrypt(String reslut) throws Exception {
        String[] resultArray = {"", "", "", ""};
        String terminalTypeId = null;
        String jdes3Key = null;//des3 密钥
        String data = null;//数据
        byte[] jdes3KeyB = null;
        String[] strArray = null;
        try {
            strArray = reslut.split("\\|");
            if (strArray.length >= 3) {
                //查询 终端类型RSA 密钥
                terminalTypeId = new String(Base64.decode(strArray[0].getBytes("UTF-8")), "UTF-8");
                Long tId = Long.parseLong(terminalTypeId);
                log.debug("tId=" + tId);

                jdes3KeyB = Base64.decode(strArray[1].getBytes("UTF-8"));

                //私钥解密
                RSAObjectC rsaEncrypt = rsaMap.get(tId);
                if (null == rsaEncrypt) {//获取终端类型
                    TerminalType terminalType = terminalTypeService.searchTerminalTypeById(tId);
                    rsaEncrypt = RSAObjectC.getInstance(terminalType.getPublicKey(), terminalType.getPrivateKey());
                    rsaMap.put(tId, rsaEncrypt);
                }

                String isNewRSA = (String) getRequest().getAttribute("isNewRSA");
                if ("1".equals(isNewRSA)) {//
                    jdes3Key = new String(rsaEncrypt.decryptNew(rsaEncrypt.getPrivateKey(), jdes3KeyB));
                } else {
                    jdes3Key = new String(rsaEncrypt.decrypt(rsaEncrypt.getPrivateKey(), jdes3KeyB));
                }

                //###由于 Object C 加密的数据解密后 前面出现一堆乱码但是后面却是正确的密钥  所有需要截取字符串
                jdes3Key = jdes3Key.substring(jdes3Key.length() - 32);
                log.debug("截取32位动态des3Key=" + jdes3Key);
                data = Des3.decode(strArray[2], jdes3Key);

                if (data.length() < 1000) {
                    log.debug("解析数据：" + data);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("终端号1：" + terminalTypeId + " 解析报文错误！");
        }
        resultArray[0] = terminalTypeId;
        resultArray[1] = jdes3Key;
        resultArray[2] = data;
        return resultArray;
    }

    /**
     * 检测是否允许roleId 为空
     *
     * @param action
     * @return
     */
    public static boolean isAllowRoleIdIsNull(String action) {
        if ("bankAction_searchBankList".equals(action) || //1.1.1、获得银行
                "userAction_firstNextBnRegister".equals(action) || //1.1.2、第一个按钮下一步（注册时，检验数据）
                "userAction_register".equals(action) ||//1.1.3、用户注册
                //"userAction_login".equals(action) ||//1.1.4、登录
                "userAction_searchMobileByBankCard".equals(action) ||//1.1.5、查询用户名（刷卡登录  步骤1）
                "bankAction_searchBranchesBankList".equals(action) //1.1.12、查询支行
                ) return true;
        return false;
    }


    //=================新的加密

    /**
     * 终端——>服务器
     * BASE64(终端类型号)|BASE64(RSA(报文加密密钥))|BASE64(3DES(报文原文))
     * 服务器——>终端
     * 正常响应格式：1|BASE64(3DES(报文))|BASE64(MD5(报文))
     * 错误响应格式：0|错误码|BASE64(错误描述)
     *
     * @return
     */
    public String forwardControlNew() {
        getRequest().setAttribute("isNewRSA", "1");
        return "fc";
    }

    /**
     * 保存 RSA 密钥对象
     * 每次初始化密钥  都需要一定时间    优化效率
     */
    private static Map<Long, RSAObjectC> rsaMap = new HashMap<Long, RSAObjectC>();
}
